package com.seago.iceberg.config;

import com.seago.iceberg.repository.IcebergRepository;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.core.type.filter.AssignableTypeFilter;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Set;

/**
 * Title:
 * <p>
 * description:
 *
 * @Company: 中国船舶集团海舟系统技术有限公司-武汉
 * @author: yangs
 * @since: 2023-05-09 09:30
 * @version: 1.0
 **/
public class IcebergRepositoryScanner implements BeanDefinitionRegistryPostProcessor, EnvironmentAware {

	public static final String ICEBERG_BASE_PACKAGE = "seago.iceberg.basePackage";

	private Environment environment;

	@Override
	public void setEnvironment(Environment environment) {
		this.environment = environment;
	}

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		// 扫描指定包下的所有继承自 IcebergRepository 的接口
		ClassPathScanningCandidateComponentProviderSupport provider = new ClassPathScanningCandidateComponentProviderSupport(false);
		provider.addIncludeFilter(new AssignableTypeFilter(IcebergRepository.class));
		String[] basePackages = new String[]{environment.getProperty(ICEBERG_BASE_PACKAGE)};

		for (String basePackage : basePackages) {
			Set<BeanDefinition> beanDefinitions = provider.findCandidateComponents(basePackage);

			// 为找到的每个接口创建对应的 IcebergRepositoryFactoryBean，并注册为 Spring Bean
			for (BeanDefinition beanDefinition : beanDefinitions) {
				String repositoryClassName = beanDefinition.getBeanClassName();

				try {
					Class<?> repositoryClass = Class.forName(repositoryClassName);
					Type[] genericTypes = ((ParameterizedType) repositoryClass.getGenericInterfaces()[0]).getActualTypeArguments();
					Class<?> entityType = (Class<?>) genericTypes[0];
					Class<?> idType = (Class<?>) genericTypes[1];

					GenericBeanDefinition factoryBeanDefinition = new GenericBeanDefinition();
					factoryBeanDefinition.setBeanClass(IcebergRepositoryFactoryBean.class);
					factoryBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(repositoryClass);
					factoryBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(entityType);
					factoryBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(idType);

					registry.registerBeanDefinition(repositoryClassName, factoryBeanDefinition);
				} catch (ClassNotFoundException e) {
					throw new IllegalStateException("Failed to register IcebergRepository bean", e);
				}
			}
		}
	}

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Nothing to do here
	}
}

